<?php

namespace App\Http\Model;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class Medal extends Base
{
    protected $table = 'medal';
    protected $medalClassTable = 'medal_class';
    protected $medalUserTable = 'medal_user';
    protected $redisKeyMedalUser = 'CACHE:MEDAL:USER:';
    protected $redisKeyMedalUserPrivate = 'MEDAL:USER:PRIVATE';// 用户勋章是否公开或私密

    public function __construct(array $attributes = [])
    {
        parent::__construct($this->table, $attributes);
    }

    /**
     * 用户勋章是否公开或私密
     *
     * @param int $operateType 操作类型 默认0=读取，1=写入
     * @param int $userId 用户ID
     * @param int $status 是否公开或私密 默认0=公开，1=私密
     * @return bool
     * */
    public function medalUserPrivate($operateType = 0, $userId = 0, $status = 0)
    {
        $result = 0;

        switch ($operateType) {
            case 0:
                if (Redis::hexists($this->redisKeyMedalUserPrivate, $userId)) {
                    $result = intval(Redis::hget($this->redisKeyMedalUserPrivate, $userId));
                }
                break;
            case 1:
                $ret = Redis::hmset($this->redisKeyMedalUserPrivate, [$userId => $status]);
                if ($ret) {
                    $result = $status;
                }
                break;
            default:
                break;
        }

        return $result;
    }

    /**
     * 获取勋章列表
     *
     * @param int $userId 用户ID
     * @param int $checkUserId 查看用户ID
     * @param int $classId 类别ID（仅支持父类ID）
     * @return array
     * */
    public function getMedalList($userId = 0, $checkUserId = 0, $classId = 0)
    {
        $data = [];

        do {
            // 查询父类
            $checkParentParams = ['pid' => 0, 'is_show' => 1];
            if ($classId > 0) {
                $checkParentParams['class_id'] = $classId;
            }
            $getParentMedalClassList = $this->getMedalClassList($checkParentParams);
            if (empty($getParentMedalClassList)) {
                break;
            }

            // 查询子类
            $getSubMedalClassList = $this->getMedalClassList(['is_show' => 1], array_column($getParentMedalClassList, 'class_id'));
            if (empty($getSubMedalClassList)) {
                break;
            }
            //排序（游戏勋章放到最上面）
            $orderBy = array_column($getSubMedalClassList, 'class_id');
            array_multisort($orderBy, SORT_DESC, $getSubMedalClassList);

            // 合并 父、子 分类数据
            $getMedalClassList = array_merge($getParentMedalClassList, $getSubMedalClassList);

            $getMedalClassIdArray = [];
            $getMedalClassKeyIdArray = [];

            foreach ($getMedalClassList as $key => $value) {
                $getMedalClassIdArray[] = $value['class_id'];
                $getMedalClassKeyIdArray[$value['class_id']] = $value['class_id'];

                $getMedalClassList[$key]['item'] = [];
            }

            $sameUserFlag = true;// 相同用户标识 true=同一用户 false=不是同一用户
            $useUserId = $userId;
            if ($checkUserId > 0 and $userId != $checkUserId) {
                $sameUserFlag = false;
                $useUserId = $checkUserId;
            }

            // 用户勋章是否公开或私密
            $medalUserPrivateStatus = $this->medalUserPrivate(0, $useUserId);

            // 查询所有该用户的用户勋章数据
            $getMedalUserList = $this->getMedalUserListCache([$useUserId], true, false);
            $getMedalUserList = $getMedalUserList[0] ?? [];
            // 判断不是同一用户 用户勋章设置1=私密 则置空勋章
            if (!$sameUserFlag and $medalUserPrivateStatus == 1) {
                $getMedalUserList = [];
            }

            // 用户勋章是否公开或私密状态
            $data['medal_user_private_status'] = $medalUserPrivateStatus;
            // 用户勋章总数
            $data['medal_user_count'] = count($getMedalUserList);


            $getAlreadyMedalIdByCreatedAtArray = [];// 创建时间
            $getAlreadyMedalIdByExpireTimeArray = [];// 过期时间
            if (!empty($getMedalUserList)) {
                $getAlreadyMedalIdByCreatedAtArray = array_column($getMedalUserList, 'created_at', 'medal_id');
                $getAlreadyMedalIdByExpireTimeArray = array_column($getMedalUserList, 'expire_time', 'medal_id');
            }

            // 查询勋章
            $getMedalCheckList = $this->getMedalCheckList([]);
            foreach ($getMedalCheckList as $key => $value) {
                if (array_key_exists($value['class_id'], $getMedalClassKeyIdArray)) {
                    $classIndex = array_search($value['class_id'], $getMedalClassIdArray);

                    // unset($value['class_id']);

                    $value['is_enabled'] = 0;
                    // 检测是否已佩戴勋章
                    if (array_key_exists($value['medal_id'], $getAlreadyMedalIdByCreatedAtArray)) {
                        // 是否可用
                        $value['is_enabled'] = 1;

                        // 获得时间
                        $value['acquire_time'] = date('Y.m.d', $getAlreadyMedalIdByCreatedAtArray[$value['medal_id']]);

                        // 剩余天数
                        if ($getAlreadyMedalIdByExpireTimeArray[$value['medal_id']] == 0) {
                            $value['day'] = $getAlreadyMedalIdByExpireTimeArray[$value['medal_id']];
                        } elseif ($getAlreadyMedalIdByExpireTimeArray[$value['medal_id']] > time()) {
                            $remainDay = secondConvert($getAlreadyMedalIdByExpireTimeArray[$value['medal_id']] - time());
                            if (($remainDay['day'] == 0)) {
                                $remainDay['day'] = 1;
                            }
                            $value['day'] = $remainDay['day'];
                        }
                    }

                    // 勋章图片构建
                    $this->medalBuildImage($value);
                    $getMedalClassList[$classIndex]['item'][] = $value;
                }
            }

            // 引用算法
            $data['list'] = quoteTree($getMedalClassList, 'class_id', 'pid');

            // 处理数组字段
            foreach ($data['list'] as $key => $value) {
                // unset($data['list'][$key]['class_id']);
                unset($data['list'][$key]['pid']);
                unset($data['list'][$key]['is_similar_use']);
                unset($data['list'][$key]['is_show']);

                if (isset($value['sub_item'])) {
                    foreach ($value['sub_item'] as $itemKey => $itemValue) {
                        // unset($data['list'][$key]['sub_item'][$itemKey]['class_id']);
                        unset($data['list'][$key]['sub_item'][$itemKey]['pid']);
                        unset($data['list'][$key]['sub_item'][$itemKey]['is_similar_use']);
                        unset($data['list'][$key]['sub_item'][$itemKey]['is_show']);
                    }
                } else {
                    $data['list'][$key]['sub_item'] = [];
                }
            }

        } while (false);

        return $data;
    }

    /**
     * 勋章图片构建
     *
     * @param array $data 勋章数据
     * */
    public function medalBuildImage(&$data = [])
    {
        $fieldImage = ['big_img', 'middle_img', 'small_img', 'big_gray_img', 'join_animation'];
        foreach ($fieldImage as $value) {
            if (isset($data[$value])) {
                $data[$value] = build_image($data[$value]);
            }
        }
    }

    /**
     * 勋章-查询多条
     *
     * @param array $condition 条件
     * @param array $orCondition 或条件
     * @return array
     * */
    public function getMedalCheckList($condition = [], $orCondition = [])
    {
        $db = DB::table($this->table);
        if (empty($orCondition)) {
            $db->where($condition);
        } else {
            foreach ($orCondition as $key => $value) {
                if ($key == 0) {
                    $db->where([
                        ['day', '=', 0],
                        [$value, '>', 0],
                    ]);
                } else {
                    $db->orWhere('day', '=', 0)
                        ->where($value, '>', 0);
                }
            }
        }
        $data = $db->orderBy('sort_number', 'asc')->get()->toArray();
        return self::objToArray($data);
    }

    /**
     * 勋章-查询单条
     *
     * @param array $condition 条件
     * @return array
     * */
    public function getMedalSingle($condition)
    {
        $data = DB::table($this->table)
            ->where($condition)
            ->first();
        return self::objToArray($data);
    }

    /**
     * 勋章-创建
     *
     * @param array $data 数据
     * @return bool
     * */
    public function createMedal($data)
    {
        return DB::table($this->table)->insertGetId($data);
    }

    /**
     * 勋章-更新
     *
     * @param array $condition 条件
     * @param array $data 数据
     * @return bool
     * */
    public function updateMedal($condition, $data)
    {
        return DB::table($this->table)->where($condition)->update($data);
    }

    /**
     * 勋章-删除
     *
     * @param array $condition 条件
     * @return bool
     * */
    public function removeMedal($condition)
    {
        return DB::table($this->table)->where($condition)->delete();
    }

    ########## 勋章分类 ##################################################

    /**
     * 勋章分类-查询多条
     *
     * @param array $condition 条件
     * @param array $pidWhereIn 父类ID in条件
     * @return array
     * */
    public function getMedalClassList($condition, $pidWhereIn = null)
    {
        $db = DB::table($this->medalClassTable);
        $db->where($condition);
        if (!empty($pidWhereIn) and is_array($pidWhereIn)) {
            $db->whereIn('pid', $pidWhereIn);
        }
        $data = $db->get()->toArray();
        return self::objToArray($data);
    }

    /**
     * 勋章分类-查询单条
     *
     * @param array $condition 条件
     * @return array
     * */
    public function getMedalClassSingle($condition)
    {
        $data = DB::table($this->medalClassTable)
            ->where($condition)
            ->first();
        return self::objToArray($data);
    }

    /**
     * 勋章分类-创建
     *
     * @param array $data 数据
     * @return bool
     * */
    public function createMedalClass($data)
    {
        return DB::table($this->medalClassTable)->insertGetId($data);
    }

    /**
     * 勋章分类-更新
     *
     * @param array $condition 条件
     * @param array $data 数据
     * @return bool
     * */
    public function updateMedalClass($condition, $data)
    {
        return DB::table($this->medalClassTable)->where($condition)->update($data);
    }

    /**
     * 勋章分类-删除
     *
     * @param int $classId 分类ID
     * @param bool $removeSubFlag 删除子类标识
     * @return bool
     * */
    public function removeMedalClass($classId, $removeSubFlag = false)
    {
        $db = DB::table($this->medalClassTable)->where(['class_id' => $classId]);

        if ($removeSubFlag) {
            $db->orWhere(['pid' => $classId]);
        }

        return $db->delete();
    }

    ########## 用户勋章 ##################################################

    /**
     * 用户勋章-列表缓存
     *
     * @param array $userIds 用户ID组
     * @param bool $isShowFieldAll 是否显示所有字段 默认 true=是
     * @param bool $isShowOnlyUse 是否【只】显示已使用数据 默认 true=是
     * @return array
     * */
    public function getMedalUserListCache($userIds, $isShowFieldAll = true, $isShowOnlyUse = true)
    {
        $data = [];

        do {
            if (empty($userIds) or !is_array($userIds)) {
                break;
            }

            $data = Redis::MGET(array_map(function ($userId) {
                return $this->redisKeyMedalUser . $userId;
            }, $userIds));

            foreach ($data as $key => $value) {
                if (empty($value)) {
                    unset($data[$key]);
                    continue;
                }
                $data[$key] = json_decode($value, true);
                unset($userIds[$key]);
            }
            if (empty($userIds)) {
                break;
            }

            $getMedalUserByIdsData = $this->getMedalUserByIds($userIds);
            if (empty($getMedalUserByIdsData)) {
                // 默认存储为空
                foreach ($userIds as $idVal) {
                    Redis::setex($this->redisKeyMedalUser . $idVal, 3600, json_encode([], JSON_UNESCAPED_UNICODE));
                }
                $dataGroup = [];
            } else {
                // 根据用户ID分组 并根据用户ID存入Cache
                $dataGroup = dataGroup($getMedalUserByIdsData, 'user_id');
                foreach ($dataGroup as $userIdVal => $item) {
                    Redis::setex($this->redisKeyMedalUser . $userIdVal, 3600, json_encode($item, JSON_UNESCAPED_UNICODE));
                }
            }

            $data = array_merge($data, $dataGroup);

        } while (false);

        // 过滤空数组，处理字段显示移除item
        foreach ($data as $index => $item) {
            if (empty($item)) {
                unset($data[$index]);
                continue;
            }

            foreach ($item as $key => $value) {
                if ($isShowOnlyUse and $value['is_use'] == 0) {
                    unset($data[$index][$key]);
                    continue;
                }

                if (!$isShowFieldAll) {
                    $data[$index][$key] = [
                        'user_id' => $value['user_id'],
                        'class_id' => $value['class_id'],
                        'medal_id' => $value['medal_id'],
                        'medal_name' => $value['medal_name'],
                        'big_img' => $value['big_img'],
                        'middle_img' => $value['middle_img'],
                        'small_img' => $value['small_img'],
                    ];
                    if (!empty($value['join_animation'])) {
                        $data[$index][$key]['join_animation'] = $value['join_animation'];
                    }
                }
            }
            $data[$index] = array_values($data[$index]);
        }

        return array_values($data);
    }

    /**
     * 用户勋章-根据用户ID组-查询多条
     *
     * @param array $userIds 用户ID组
     * @return array
     * */
    private function getMedalUserByIds($userIds)
    {
        $data = DB::table($this->medalUserTable)
            ->leftJoin($this->table, $this->medalUserTable . '.medal_id', '=', $this->table . '.medal_id')
            ->where([
                ['expire_time', '=', 0],
            ])
            ->whereIn('user_id', $userIds)
            ->orWhere('expire_time', '>', time())
            ->whereIn('user_id', $userIds)
            ->orderBy('class_id','asc')
            ->get()
            ->toArray();
        $data = self::objToArray($data);

        foreach ($data as $key => $value) {
            $this->medalBuildImage($value);
            $data[$key] = $value;
        }

        return $data;
    }

    /**
     * 用户勋章-查询多条
     *
     * @param array $condition 查询条件
     * @return array
     * */
    private function getAllMedalUserByIds($userIds)
    {
        $data = DB::table($this->medalUserTable)
            ->whereIn('user_id',$userIds)
            ->orderBy('medal_user_id')
            ->get()
            ->toArray();
        $data = self::objToArray($data);

        foreach ($data as $key => $value) {
            $this->medalBuildImage($value);
            $data[$key] = $value;
        }

        return $data;
    }

    /**
     * 用户勋章-查询单条
     *
     * @param array $condition 条件
     * @param bool $isCheckExpireTime 是否校验过期时间 默认 true
     * @return array
     * */
    public function getMedalUserSingle($condition, $isCheckExpireTime = true)
    {
        if (isset($condition['medal_id'])) {
            $condition[$this->medalUserTable . '.medal_id'] = $condition['medal_id'];
            unset($condition['medal_id']);
        }
        $data = DB::table($this->medalUserTable)
            ->leftJoin($this->table, $this->medalUserTable . '.medal_id', '=', $this->table . '.medal_id')
            ->where($condition)
            ->first();
        $data = self::objToArray($data);

        // 判断是否已过期
        if (!empty($data)) {
            if ($isCheckExpireTime and $data['expire_time'] > 0 and $data['expire_time'] <= time()) {
                return [];
            }

            $this->medalBuildImage($data);
        }

        return $data;
    }

    /**
     * 用户勋章-创建/更新
     *
     * @param array $data 数据
     * @param string $type 操作类型 默认 insert=创建，update=更新，increment=累加，insertBatch=批量创建
     * @return bool
     * */
    public function updateOrInsertMedalUser($data, $type = 'insert')
    {
        $timestamp = time();

        switch ($type) {
            case 'insert':
                // 创建用户勋章数据
                $ret = DB::table($this->medalUserTable)->insertGetId([
                    'user_id' => $data['user_id'],
                    'medal_id' => $data['medal_id'],
                    'expire_time' => $data['expire_time'],
                    'created_at' => $timestamp,
                    'updated_at' => $timestamp,
                ]);
                break;
            case 'update':// 已过期，描述为续费标准 更新数据的新过期时间  expire_time 为过期时间戳
                $ret = DB::table($this->medalUserTable)->where(['medal_user_id' => $data['medal_user_id']])->update([
                    'expire_time' => $data['expire_time'],
                    'updated_at' => $timestamp,
                ]);
                break;
            case 'increment':// 未过期，描述为续费标准 累加过期时间  expire_time 为累加值秒数【存在值为0时表示永久数据】
                if ($data['expire_time'] == 0) {
                    $ret = DB::table($this->medalUserTable)->where(['medal_user_id' => $data['medal_user_id']])->update([
                        'expire_time' => $data['expire_time'],
                        'updated_at' => $timestamp,
                    ]);
                } else {
                    $ret = DB::table($this->medalUserTable)->where(['medal_user_id' => $data['medal_user_id']])->increment('expire_time', $data['expire_time'], ['updated_at' => $timestamp]);
                }
                break;
            case 'insertBatch':
                //该表存在唯一索引，必须区分出写入的和更新的
                $userIds = array_column($data, 'user_id');
                $userIds = array_merge(array_unique($userIds));
                $medals = $this->getAllMedalUserByIds($userIds);
                $tmp = [];
                $add = $update = [];
                foreach ($medals as $m) {
                    $tmp[$m['user_id'] . '_' . $m['medal_id']] = [
                        'medal_user_id' => $m['medal_user_id'],
                        'expire_time' => $m['expire_time'],
                    ];
                }
                foreach ($data as $d) {
                    $k = $d['user_id'] . '_' . $d['medal_id'];
                    if (isset($tmp[$k])) {
                        if ($d['expire_time'] != $tmp[$k]['expire_time']) {
                            //更新的数据
                            $update[] = [
                                'user_id' => $d['user_id'],
                                'medal_user_id' => $tmp[$k]['medal_user_id'],
                                'expire_time' => $d['expire_time'],
                            ];
                        }
                    } else {
                        //写入的数据
                        $add[] = $d;
                    }
                }
                
                //需要写入的
                if (count($add) > 0) {
                    DB::table($this->medalUserTable)->insert($add);
                }

                //需要更新的
                if (count($update) > 0) {
                    foreach ($update as $u) {
                        $this->updateOrInsertMedalUser($u, 'increment');
                    }
                }
                $ret = true;
                break;
            default:
                $ret = false;
                break;
        }

        if ($ret) {
            if ($type == 'insertBatch') {
                $redisKeyRemoveUserIds = [];
                foreach ($data as $key => $value) {
                    $redisKeyRemoveUserIds[] = $this->redisKeyMedalUser . $value['user_id'];
                }
                Redis::del($redisKeyRemoveUserIds);
            } else {
                Redis::del($this->redisKeyMedalUser . $data['user_id']);
            }
        }

        return $ret;
    }

    /**
     * 用户勋章-更新
     *
     * @param array $condition 条件
     * @param array $data 数据
     * @return bool
     * */
    public function updateMedalUser($condition, $data)
    {
        $ret = DB::table($this->medalUserTable)->where($condition)->update($data);
        if ($ret and isset($condition['user_id'])) {
            Redis::del($this->redisKeyMedalUser . $condition['user_id']);
        }
        return $ret;
    }

    /**
     * 用户勋章-删除
     *
     * @param array $condition 条件
     * @param int $userId 用户ID
     *
     * @return bool
     * */
    public function removeMedalUser($condition, $userId = 0)
    {
        $ret = DB::table($this->medalUserTable)->where($condition)->delete();

        if ($ret and $userId > 0) {
            Redis::del($this->redisKeyMedalUser . $userId);
        }

        return $ret;
    }

    /**
     * 根据勋章CLASS 获取数据
     *
     * @param int $classId 分类ID
     * @return array
     * */
    public function getMedalByClassId($classId)
    {
        $result = DB::table($this->table)->where(['class_id' => $classId])->orderBy("sort_number", "asc")->get();
        return self::objToArray($result);
    }
}